#include "USBController.h"

#include <WINDOWS.H>
#include <usbioctl.h>

#define BUFFER_SIZE 2048

USBController::USBController(void)
: m_controllerIndex(0), m_pUSBHub(NULL)
{
}

USBController::~USBController(void)
{
	DeleteUSBHub();
}

USBHub* USBController::GetRootHub()
{
	DeleteUSBHub();

	HANDLE hController = CreateFile(m_controllerDevicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (hController != INVALID_HANDLE_VALUE)
	{
		BYTE *buffer = new BYTE[BUFFER_SIZE];
		if (buffer)
		{
			USB_ROOT_HUB_NAME *pHubName = (USB_ROOT_HUB_NAME*)buffer;
			DWORD bytesReturned;
			if (DeviceIoControl(hController, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, pHubName, BUFFER_SIZE, &bytesReturned, NULL))
			{
				std::wstring devicePath = L"\\\\.\\";
				devicePath += pHubName->RootHubName;

				m_pUSBHub = new USBHub();
				m_pUSBHub->SetDevicePath(devicePath.c_str());

				HANDLE hHub = CreateFile(m_pUSBHub->GetDevicePath().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
				if (hHub != INVALID_HANDLE_VALUE)
				{
					USB_NODE_INFORMATION nodeInfo;
					nodeInfo.NodeType = UsbHub;
					if (DeviceIoControl(hHub, IOCTL_USB_GET_NODE_INFORMATION, &nodeInfo, sizeof(nodeInfo), &nodeInfo, sizeof(nodeInfo), &bytesReturned, NULL))
					{
						m_pUSBHub->SetBusPowered(nodeInfo.u.HubInformation.HubIsBusPowered ? true : false);
						m_pUSBHub->SetPortCount(nodeInfo.u.HubInformation.HubDescriptor.bNumberOfPorts);
					}

					CloseHandle(hHub);
				}
			}

			delete [] buffer;
		}

		CloseHandle(hController);
	}

	return m_pUSBHub;
}

void USBController::DeleteUSBHub()
{
	if (m_pUSBHub)
	{
		delete m_pUSBHub;
		m_pUSBHub = NULL;
	}
}